using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls.Primitives;

namespace Microsoft.Phone.Controls
{
    /// <summary>
    /// Simple basic implementation of <see cref="IDateTimePickerPage"/> as alternative to <see cref="LoopingSelector"/>-based default toolkit page.
    /// </summary>
    public class RangedBasedDatePickerPage : PhoneApplicationPage, IDateTimePickerPage
    {
        private const int DefaultDaysCount = 14;
        private DateTime? _value;
        private ExtendedDateTimeWrapper _valueTmp;
        private readonly List<ExtendedDateTimeWrapper> _dates = new List<ExtendedDateTimeWrapper>();

        /// <summary>
        /// .ctor
        /// </summary>
        protected RangedBasedDatePickerPage()
            : this(DateTime.Today, DefaultDaysCount)
        {

        }

        /// <summary>
        /// .ctor
        /// </summary>
        /// <param name="daysCount">Days count to be ranged.</param>
        protected RangedBasedDatePickerPage(int daysCount)
            : this(DateTime.Today, daysCount)
        {

        }

        /// <summary>
        /// .ctor
        /// </summary>
        /// <param name="startDate">Start Date</param>
        protected RangedBasedDatePickerPage(DateTime startDate)
            : this(startDate, DefaultDaysCount)
        {

        }

        /// <summary>
        /// .ctor
        /// </summary>
        /// <param name="startDate">Start Date</param>
        /// <param name="daysCount">Days count to be ranged.</param>
        protected RangedBasedDatePickerPage(DateTime startDate, int daysCount)
        {
            StateKeyValue = string.Concat(GetType().Name, "_State_Value");

            for (var i = 0; i < daysCount; i++)
            {
                _dates.Add(new ExtendedDateTimeWrapper(startDate.AddDays(i)));
            }
        }

        /// <summary>
        /// Gets KEY for Value property to be marked in State of the phone.
        /// </summary>
        protected string StateKeyValue { get; private set; }

        /// <summary>
        /// Gets wrapped ranged dates enumeration.
        /// </summary>
        protected IEnumerable<ExtendedDateTimeWrapper> Dates { get { return _dates.ToArray(); } }

        /// <summary>
        /// Performs update selection actions.
        /// </summary>
        protected virtual void UpdateSelection()
        {
            
        }
        
        /// <summary>
        /// Closes page.
        /// </summary>
        protected virtual void Close()
        {
            NavigationService.GoBack();
        }

        /// <summary>
        /// This method is called when the hardware Back button is pressed.
        /// </summary>
        /// <param name="e">Set e.Cancel to true to indicate that the request was handled by the application.</param>
        protected override void OnBackKeyPress(CancelEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            e.Cancel = true;

            Close();
        }

        /// <summary>
        /// Handles selection changed event.
        /// </summary>
        /// <param name="sender">target</param>
        /// <param name="e">arguments</param>
        protected void OnDataSourceSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e == null || e.AddedItems.Count <= 0) return;

            _valueTmp = (ExtendedDateTimeWrapper)e.AddedItems[0];
            _value = _valueTmp.DateTime;

            Close();
        }

        /// <summary>
        /// Called when a page is no longer the active page in a frame.
        /// </summary>
        /// <param name="e">An object that contains the event data.</param>
        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            base.OnNavigatedFrom(e);

            if ("app://external/".Equals(e.Uri.ToString(), StringComparison.OrdinalIgnoreCase))
            {
                State[StateKeyValue] = Value;
            }
        }

        /// <summary>
        /// Called when a page becomes the active page in a frame.
        /// </summary>
        /// <param name="e">An object that contains the event data.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            base.OnNavigatedTo(e);

            if (State.ContainsKey(StateKeyValue))
            {
                Value = State[StateKeyValue] as DateTime?;

                if (NavigationService.CanGoBack)
                {
                    NavigationService.GoBack();
                }
            }
        }

        #region Implementation of IDateTimePickerPage

        /// <summary>
        /// Gets or sets the DateTime to show in the picker page and to set when the user makes a selection.
        /// </summary>
        public DateTime? Value
        {
            get { return _value; }
            set
            {
                _value = value;

                var wrapper = new ExtendedDateTimeWrapper(_value.GetValueOrDefault(DateTime.Now));

                _valueTmp = wrapper;

                UpdateSelection();
            }
        }

        #endregion
    }
}